package service

import (
	"crypto/rand"
	"crypto/sha256"
	"encoding/base64"
	"encoding/hex"
	"errors"
	"fmt"
	"strings"
	"time"

	"golang.org/x/crypto/bcrypt"
	"gorm.io/gorm"

	"project-info/src/model"
)

// OIDCService OIDC服务结构
type OIDCService struct {
}

// NewOIDCService 创建新的OIDC服务实例
func NewOIDCService() *OIDCService {
	return &OIDCService{}
}

// ==================== 客户端管理 ====================

// GetClient 根据ID获取客户端信息
func (s *OIDCService) GetClientById(id uint64) (*model.OIDCClient, error) {
	var client model.OIDCClient
	err := model.DB().Where("id = ? AND deleted = 0 AND status = 1", id).First(&client).Error
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, fmt.Errorf("客户端不存在")
		}
		return nil, err
	}
	return &client, nil
}

// GetClient 根据客户端ID获取客户端信息
func (s *OIDCService) GetClient(clientID string) (*model.OIDCClient, error) {
	var client model.OIDCClient
	err := model.DB().Where("client_id = ? AND deleted = 0 AND status = 1", clientID).First(&client).Error
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, fmt.Errorf("客户端不存在")
		}
		return nil, err
	}
	return &client, nil
}

// ValidateClient 验证客户端凭据
func (s *OIDCService) ValidateClient(clientID, clientSecret string) (*model.OIDCClient, error) {
	client, err := s.GetClient(clientID)
	if err != nil {
		return nil, err
	}

	// 验证客户端密钥
	err = bcrypt.CompareHashAndPassword([]byte(client.ClientSecret), []byte(clientSecret))
	if err != nil {
		return nil, fmt.Errorf("客户端认证失败")
	}

	return client, nil
}

// ListClients 获取客户端列表
func (s *OIDCService) ListClients(clientName string, status int, page, pageSize int) ([]*model.OIDCClient, int64, error) {
	var clients []*model.OIDCClient
	var total int64

	// 构建查询条件
	query := model.DB().Model(&model.OIDCClient{}).Where("deleted = 0")
	if clientName != "" {
		query = query.Where("client_name LIKE ?", "%"+clientName+"%")
	}
	if status > 0 {
		query = query.Where("status = ?", status)
	}

	// 计算总数
	err := query.Count(&total).Error
	if err != nil {
		return nil, 0, err
	}

	// 分页查询
	offset := (page - 1) * pageSize
	err = query.Order("create_time DESC").Offset(offset).Limit(pageSize).Find(&clients).Error
	if err != nil {
		return nil, 0, err
	}

	return clients, total, nil
}

// CreateClient 创建客户端
func (s *OIDCService) CreateClient(client *model.OIDCClient) error {
	// 检查客户端ID是否已存在
	var count int64
	err := model.DB().Model(&model.OIDCClient{}).Where("client_id = ? AND deleted = 0", client.ClientID).Count(&count).Error
	if err != nil {
		return err
	}
	if count > 0 {
		return fmt.Errorf("客户端ID已存在")
	}

	// 加密客户端密钥
	hashedSecret, err := bcrypt.GenerateFromPassword([]byte(client.ClientSecret), bcrypt.DefaultCost)
	if err != nil {
		return err
	}
	client.ClientSecret = string(hashedSecret)

	// 设置默认值
	now := time.Now()
	client.CreateTime = &now
	client.UpdateTime = &now
	client.Status = 1
	client.Deleted = 0

	return model.DB().Create(client).Error
}

// UpdateClient 更新客户端
func (s *OIDCService) UpdateClient(id uint64, updates map[string]interface{}) error {
	// 如果更新密钥，需要加密
	if newSecret, ok := updates["client_secret"]; ok {
		hashedSecret, err := bcrypt.GenerateFromPassword([]byte(newSecret.(string)), bcrypt.DefaultCost)
		if err != nil {
			return err
		}
		updates["client_secret"] = string(hashedSecret)
	}

	now := time.Now()
	updates["update_time"] = &now
	return model.DB().Model(&model.OIDCClient{}).Where("id = ? AND deleted = 0", id).Updates(updates).Error
}

// DeleteClient 删除客户端（软删除）
func (s *OIDCService) DeleteClient(id uint64) error {
	now := time.Now()
	return model.DB().Model(&model.OIDCClient{}).Where("id = ? AND deleted = 0", id).Updates(map[string]interface{}{
		"deleted":     1,
		"update_time": &now,
	}).Error
}

// RegenerateClientSecret 重新生成客户端密钥
func (s *OIDCService) RegenerateClientSecret(id uint64) (string, error) {
	// 生成新的客户端密钥
	newSecret := s.generateRandomString(32)
	hashedSecret, err := bcrypt.GenerateFromPassword([]byte(newSecret), bcrypt.DefaultCost)
	if err != nil {
		return "", err
	}

	// 更新数据库
	now := time.Now()
	err = model.DB().Model(&model.OIDCClient{}).Where("id = ? AND deleted = 0", id).Updates(map[string]interface{}{
		"client_secret": string(hashedSecret),
		"update_time":   &now,
	}).Error
	if err != nil {
		return "", err
	}

	return newSecret, nil
}

// ==================== 授权码管理 ====================

// CreateAuthorizationCode 创建授权码
func (s *OIDCService) CreateAuthorizationCode(code *model.OIDCAuthorizationCode) error {
	now := time.Now()
	code.CreateTime = &now
	code.UpdateTime = &now
	code.Used = false
	code.Deleted = 0
	return model.DB().Create(code).Error
}

// GetAuthorizationCode 获取授权码
func (s *OIDCService) GetAuthorizationCode(code string) (*model.OIDCAuthorizationCode, error) {
	var authCode model.OIDCAuthorizationCode
	err := model.DB().Where("code = ? AND deleted = 0 AND used = 0 AND expires_at > ?", code, time.Now()).First(&authCode).Error
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, fmt.Errorf("授权码无效或已过期")
		}
		return nil, err
	}
	return &authCode, nil
}

// UseAuthorizationCode 使用授权码（标记为已使用）
func (s *OIDCService) UseAuthorizationCode(code string) error {
	now := time.Now()
	return model.DB().Model(&model.OIDCAuthorizationCode{}).Where("code = ? AND deleted = 0", code).Updates(map[string]interface{}{
		"used":        1,
		"update_time": &now,
	}).Error
}

// ==================== 令牌管理 ====================

// CreateAccessToken 创建访问令牌
func (s *OIDCService) CreateAccessToken(token *model.OIDCAccessToken) error {
	now := time.Now()
	token.CreateTime = &now
	token.UpdateTime = &now
	token.Revoked = false
	token.Deleted = 0
	return model.DB().Create(token).Error
}

// CreateRefreshToken 创建刷新令牌
func (s *OIDCService) CreateRefreshToken(token *model.OIDCRefreshToken) error {
	now2 := time.Now()
	token.CreateTime = &now2
	token.UpdateTime = &now2
	token.Revoked = false
	token.Deleted = 0
	return model.DB().Create(token).Error
}

// GetAccessToken 获取访问令牌
func (s *OIDCService) GetAccessToken(token string) (*model.OIDCAccessToken, error) {
	var accessToken model.OIDCAccessToken
	err := model.DB().Where("token = ? AND deleted = 0 AND revoked = 0 AND expires_at > ?", token, time.Now()).First(&accessToken).Error
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, fmt.Errorf("访问令牌无效或已过期")
		}
		return nil, err
	}
	return &accessToken, nil
}

// GetRefreshToken 获取刷新令牌
func (s *OIDCService) GetRefreshToken(token string) (*model.OIDCRefreshToken, error) {
	var refreshToken model.OIDCRefreshToken
	err := model.DB().Where("token = ? AND deleted = 0 AND revoked = 0 AND expires_at > ?", token, time.Now()).First(&refreshToken).Error
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, fmt.Errorf("刷新令牌无效或已过期")
		}
		return nil, err
	}
	return &refreshToken, nil
}

// RevokeToken 撤销令牌
func (s *OIDCService) RevokeToken(token string) error {
	// 尝试撤销访问令牌
	now := time.Now()
	err := model.DB().Model(&model.OIDCAccessToken{}).Where("token = ? AND deleted = 0", token).Updates(map[string]interface{}{
		"revoked":     1,
		"update_time": &now,
	}).Error
	if err != nil {
		return err
	}

	// 尝试撤销刷新令牌
	err = model.DB().Model(&model.OIDCRefreshToken{}).Where("token = ? AND deleted = 0", token).Updates(map[string]interface{}{
		"revoked":     1,
		"update_time": &now,
	}).Error

	return err
}

// RevokeTokenByID 根据令牌ID撤销令牌
func (s *OIDCService) RevokeTokenByID(id uint64, tokenType string) error {
	db := model.DB()
	now := time.Now()

	// 根据令牌类型判断是访问令牌还是刷新令牌
	switch tokenType {
	case "access":
		// 先在访问令牌中查找并撤销
		var accessToken model.OIDCAccessToken
		if err := db.Where("id = ? AND deleted = 0", id).First(&accessToken).Error; err == nil {
			return db.Model(&accessToken).Updates(map[string]interface{}{
				"revoked":     1,
				"update_time": &now,
			}).Error
		}
	case "refresh":
		// 在刷新令牌中查找并撤销
		var refreshToken model.OIDCRefreshToken
		if err := db.Where("id = ? AND deleted = 0", id).First(&refreshToken).Error; err == nil {
			return db.Model(&refreshToken).Updates(map[string]interface{}{
				"revoked":     1,
				"update_time": &now,
			}).Error
		}
	}

	return errors.New("token not found")
}

// ListTokens 获取令牌列表
func (s *OIDCService) ListTokens(clientID string, userID uint64, page, pageSize int) ([]*model.OIDCAccessToken, int64, error) {
	var tokens []*model.OIDCAccessToken
	var total int64

	query := model.DB().Model(&model.OIDCAccessToken{}).Where("deleted = 0")
	if clientID != "" {
		query = query.Where("client_id = ?", clientID)
	}
	if userID > 0 {
		query = query.Where("user_id = ?", userID)
	}

	// 计算总数
	err := query.Count(&total).Error
	if err != nil {
		return nil, 0, err
	}

	// 分页查询
	offset := (page - 1) * pageSize
	err = query.Order("create_time DESC").Offset(offset).Limit(pageSize).Find(&tokens).Error
	if err != nil {
		return nil, 0, err
	}

	return tokens, total, nil
}

// ==================== 会话管理 ====================

// CreateUserSession 创建用户会话
func (s *OIDCService) CreateUserSession(session *model.OIDCUserSession) error {
	now := time.Now()
	session.CreateTime = &now
	session.UpdateTime = &now
	session.Status = 1
	session.Deleted = 0
	return model.DB().Create(session).Error
}

// GetUserSession 获取用户会话
func (s *OIDCService) GetUserSession(sessionID string) (*model.OIDCUserSession, error) {
	var session model.OIDCUserSession
	err := model.DB().Where("session_id = ? AND deleted = 0 AND status = 1 AND expires_at > ?", sessionID, time.Now()).First(&session).Error
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, fmt.Errorf("会话不存在或已过期")
		}
		return nil, err
	}
	return &session, nil
}

// UpdateUserSession 更新用户会话活动时间
func (s *OIDCService) UpdateUserSession(sessionID string) error {
	now := time.Now()
	return model.DB().Model(&model.OIDCUserSession{}).Where("session_id = ? AND deleted = 0", sessionID).Updates(map[string]interface{}{
		"last_activity": &now,
		"update_time":   &now,
	}).Error
}

// RevokeUserSession 撤销用户会话
func (s *OIDCService) RevokeUserSession(sessionID string) error {
	now := time.Now()
	return model.DB().Model(&model.OIDCUserSession{}).Where("session_id = ? AND deleted = 0", sessionID).Updates(map[string]interface{}{
		"status":      0,
		"update_time": &now,
	}).Error
}

// ListUserSessions 获取用户会话列表
func (s *OIDCService) ListUserSessions(userID uint64, page, pageSize int) ([]*model.OIDCUserSession, int64, error) {
	var sessions []*model.OIDCUserSession
	var total int64

	query := model.DB().Model(&model.OIDCUserSession{}).Where("deleted = 0")
	if userID > 0 {
		query = query.Where("user_id = ?", userID)
	}

	// 计算总数
	err := query.Count(&total).Error
	if err != nil {
		return nil, 0, err
	}

	// 分页查询
	offset := (page - 1) * pageSize
	err = query.Order("create_time DESC").Offset(offset).Limit(pageSize).Find(&sessions).Error
	if err != nil {
		return nil, 0, err
	}

	return sessions, total, nil
}

// ==================== 作用域管理 ====================

// GetScopes 获取作用域列表
func (s *OIDCService) GetScopes(scopeNames []string) ([]*model.OIDCScope, error) {
	var scopes []*model.OIDCScope
	query := model.DB().Where("deleted = 0 AND status = 1")
	if len(scopeNames) > 0 {
		query = query.Where("scope_name IN ?", scopeNames)
	}
	err := query.Find(&scopes).Error
	return scopes, err
}

// GetDefaultScopes 获取默认作用域
func (s *OIDCService) GetDefaultScopes() ([]*model.OIDCScope, error) {
	var scopes []*model.OIDCScope
	err := model.DB().Where("deleted = 0 AND status = 1 AND is_default = 1").Find(&scopes).Error
	return scopes, err
}

// ==================== 统计信息 ====================

// GetStats 获取OIDC服务统计信息
func (s *OIDCService) GetStats() (map[string]interface{}, error) {
	stats := make(map[string]interface{})

	// 活跃会话数
	var activeSessions int64
	err := model.DB().Model(&model.OIDCUserSession{}).Where("deleted = 0 AND status = 1 AND expires_at > ?", time.Now()).Count(&activeSessions).Error
	if err != nil {
		return nil, err
	}
	stats["active_sessions"] = activeSessions

	// 活跃令牌数
	var activeTokens int64
	err = model.DB().Model(&model.OIDCAccessToken{}).Where("deleted = 0 AND revoked = 0 AND expires_at > ?", time.Now()).Count(&activeTokens).Error
	if err != nil {
		return nil, err
	}
	stats["active_tokens"] = activeTokens

	// 注册客户端数
	var registeredClients int64
	err = model.DB().Model(&model.OIDCClient{}).Where("deleted = 0").Count(&registeredClients).Error
	if err != nil {
		return nil, err
	}
	stats["registered_clients"] = registeredClients

	return stats, nil
}

// GetClientStats 获取特定客户端的统计信息
func (s *OIDCService) GetClientStats(id uint64) (map[string]interface{}, error) {
	// 验证客户端是否存在
	client, err := s.GetClientById(id)
	if err != nil {
		return nil, err
	}

	stats := make(map[string]interface{})
	stats["clientId"] = client.ClientID
	stats["clientName"] = client.ClientName

	// 统计访问令牌数量
	var accessTokenCount int64
	err = model.DB().Model(&model.OIDCAccessToken{}).Where("client_id = ? AND deleted = 0 AND revoked = 0", client.ClientID).Count(&accessTokenCount).Error
	if err != nil {
		return nil, err
	}
	stats["activeAccessTokens"] = int(accessTokenCount)

	// 统计刷新令牌数量
	var refreshTokenCount int64
	err = model.DB().Model(&model.OIDCRefreshToken{}).Where("client_id = ? AND deleted = 0 AND revoked = 0", client.ClientID).Count(&refreshTokenCount).Error
	if err != nil {
		return nil, err
	}
	stats["activeRefreshTokens"] = int(refreshTokenCount)

	// 统计授权码数量
	var authCodeCount int64
	err = model.DB().Model(&model.OIDCAuthorizationCode{}).Where("client_id = ? AND deleted = 0 AND expires_at > ?", client.ClientID, time.Now()).Count(&authCodeCount).Error
	if err != nil {
		return nil, err
	}
	stats["pendingAuthCodes"] = int(authCodeCount)

	// 统计活跃会话数量
	var sessionCount int64
	err = model.DB().Model(&model.OIDCUserSession{}).Where("client_id = ? AND deleted = 0 AND expires_at > ?", client.ClientID, time.Now()).Count(&sessionCount).Error
	if err != nil {
		return nil, err
	}
	stats["activeSessions"] = int(sessionCount)

	// 最后活动时间（简化实现）
	stats["lastActivity"] = time.Now()

	return stats, nil
}

// ==================== 清理任务 ====================

// CleanupExpiredData 清理过期数据
func (s *OIDCService) CleanupExpiredData() error {
	now := time.Now()

	// 清理过期的授权码
	err := model.DB().Model(&model.OIDCAuthorizationCode{}).Where("expires_at < ? AND deleted = 0", now).Updates(map[string]interface{}{
		"deleted":     1,
		"update_time": &now,
	}).Error
	if err != nil {
		return err
	}

	// 清理过期的访问令牌
	err = model.DB().Model(&model.OIDCAccessToken{}).Where("expires_at < ? AND deleted = 0", now).Updates(map[string]interface{}{
		"deleted":     1,
		"update_time": &now,
	}).Error
	if err != nil {
		return err
	}

	// 清理过期的刷新令牌
	err = model.DB().Model(&model.OIDCRefreshToken{}).Where("expires_at < ? AND deleted = 0", now).Updates(map[string]interface{}{
		"deleted":     1,
		"update_time": &now,
	}).Error
	if err != nil {
		return err
	}

	// 清理过期的用户会话
	err = model.DB().Model(&model.OIDCUserSession{}).Where("expires_at < ? AND deleted = 0", now).Updates(map[string]interface{}{
		"status":      0,
		"deleted":     1,
		"update_time": &now,
	}).Error

	return err
}

// ==================== 工具方法 ====================

// generateRandomString 生成随机字符串
func (s *OIDCService) generateRandomString(length int) string {
	bytes := make([]byte, length)
	_, err := rand.Read(bytes)
	if err != nil {
		// 如果随机数生成失败，使用时间戳作为种子
		hash := sha256.Sum256([]byte(fmt.Sprintf("%d", time.Now().UnixNano())))
		return hex.EncodeToString(hash[:])[:length]
	}
	return base64.URLEncoding.EncodeToString(bytes)[:length]
}

// ValidateRedirectURI 验证重定向URI
func (s *OIDCService) ValidateRedirectURI(client *model.OIDCClient, redirectURI string) bool {
	for _, uri := range client.RedirectURIs {
		if uri == redirectURI {
			return true
		}
	}
	return false
}

// ValidateScope 验证作用域
func (s *OIDCService) ValidateScope(client *model.OIDCClient, requestedScopes []string) bool {
	for _, requestedScope := range requestedScopes {
		found := false
		for _, clientScope := range client.Scopes {
			if clientScope == requestedScope {
				found = true
				break
			}
		}
		if !found {
			return false
		}
	}
	return true
}

// ParseScope 解析作用域字符串
func (s *OIDCService) ParseScope(scopeStr string) []string {
	if scopeStr == "" {
		return []string{}
	}
	return strings.Fields(scopeStr)
}

// JoinScope 连接作用域数组
func (s *OIDCService) JoinScope(scopes []string) string {
	return strings.Join(scopes, " ")
}
